const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')
const { target, formats, targets: allTargets } = require('./tool/args')
const { gzipSync } = require('zlib')
const { packages, run } = require('./util')
const defBuildTypes = ['umd', 'esm']

main()

async function main() {
  const targets = target ? target.split(',') : allTargets
  await buildAll(targets)
  checkAllSizes(targets)
}

async function buildAll(targets) {
  await runParallel(require('os').cpus().length, targets, build)
}
/**
 * 开启多线程打包
 * @param {*} maxConcurrency 最大值
 * @param {*} source 目标对象
 * @param {*} iteratorFn 执行方法
 * @returns
 */
async function runParallel(maxConcurrency, source, iteratorFn) {
  const ret = []
  const executing = []
  for (const item of source) {
    const p = Promise.resolve().then(() => iteratorFn(item, source))
    ret.push(p)
    // 如果任务数量大于线程数量
    if (maxConcurrency <= source.length) {
      const e = p.then(() => executing.splice(executing.indexOf(e), 1))
      executing.push(e)
      if (executing.length >= maxConcurrency) {
        await Promise.race(executing)
      }
    }
  }
  return Promise.all(ret)
}

async function build(target) {
  const pkgDir = path.join(packages, target)
  const pkg = require(`${pkgDir}/package.json`)
  if (pkg.private) {
    return
  }
  // if building a specific format, do not remove dist.
  await fs.remove(`${pkgDir}/dist`)
  await run('rollup', [
    '-c',
    '--environment',
    [
      `NODE_ENV:production`,
      `TARGET:${target}`,
      `FORMATS:${formats || defBuildTypes.join(' ')}`
    ]
      .filter(Boolean)
      .join(',')
  ])
}

function checkAllSizes(targets) {
  console.log()
  for (const target of targets) {
    checkSize(target)
  }
  console.log()
}

function checkSize(target) {
  const pkgDir = path.join(packages, target)
  defBuildTypes.forEach(type => {
    checkFileSize(path.join(pkgDir, `/dist/${target}.${type}.js`))
  })
}

function checkFileSize(filePath) {
  if (!fs.existsSync(filePath)) {
    return
  }
  const file = fs.readFileSync(filePath)
  const minSize = (file.length / 1024).toFixed(2) + 'kb'
  const gzipped = gzipSync(file)
  const gzippedSize = (gzipped.length / 1024).toFixed(2) + 'kb'
  console.log(
    `${chalk.gray(
      chalk.bold(path.basename(filePath))
    )} min:${minSize} / gzip:${gzippedSize} `
  )
}
